using System;
using System.Collections.Generic;
using System.Linq;
using Pay.DTO;
using Pay.IService;
using Pay.Data;
using Pay.Service.Cache;
using Pay.Core;
using Pay.TO;

namespace Pay.Service {
    public class CategoryService : ServiceBase, ICategoryService, IDisposable {
        private IUnitOfWork _iUnitOfWork;
        private IMerchantService _iMerchantService;

        public CategoryService(IUnitOfWork iUnitOfWork, IMerchantService iMerchantService) : base(iUnitOfWork) {
            _iUnitOfWork = iUnitOfWork;
            _iMerchantService = iMerchantService;
        }

        #region 拓垦商城
        /// <summary>
        /// 获得产品品类分页列表
        /// </summary>
        /// <param name="query"></param>
        /// <param name="merchant_id"></param>
        /// <returns></returns>
        public PagedResult<token_category_dto> GetCategoryPageList(CategoryQuery query, long merchant_id) {
            var filter = PredicateBuilder.True<Category>();
            filter = filter.And(c => c.MerchantId == merchant_id && c.Depth == query.depth && c.IsDeleted == false);
            if (!string.IsNullOrEmpty(query.name))
                filter = filter.And(c => c.Name == query.name);
            if (!string.IsNullOrEmpty(query.is_disable)) {
                bool value = int.Parse(query.is_disable) == 1 ? true : false;
                filter = filter.And(c => c.IsDisabled == value);
            }
            if (!string.IsNullOrEmpty(query.begin_time)) {
                DateTime time = DateTime.Parse(query.begin_time);
                filter = filter.And(c => c.UpdateTime >= time);
            }
            if (!string.IsNullOrEmpty(query.end_time)) {
                DateTime time = DateTime.Parse(query.end_time).AddDays(1);
                filter = filter.And(c => c.UpdateTime <= time);
            }

            var q = from c in context.Categories.Where(filter)
                    join pc in context.Categories.Where(c => c.IsDeleted == false) on c.ParentId equals pc.Id into t1
                    from tpc in t1.DefaultIfEmpty()
                    select new token_category_dto() {
                        id = c.Id,
                        name = c.Name,
                        parent_id = c.ParentId,
                        parent_name = tpc != null ? tpc.Name : "",
                        sort = c.Sort,
                        update_time = c.UpdateTime,
                        is_disabled = c.IsDisabled,
                        is_deleted = c.IsDeleted,
                        type = c.Type
                    };
            var rows = q.OrderBy(c => c.sort).Skip((query.page - 1) * query.size).Take(query.size).ToList();
            var result = new PagedResult<token_category_dto>(rows, q.Count(), query.page, query.size);
            return result;
        }
        /// <summary>
        /// 获取拓垦的分类
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public token_category_dto GetTokenCategory(long id) {
            return context.Categories.Where(s=>s.Id==id).FromCacheFirstOrDefault<Category, token_category_dto>("Category");
        }

        /// <summary>
        /// 获取一级分类列表 0 商城 1 集市
        /// </summary>
        /// <returns></returns>
        public List<token_category_dto> GetTokenFirstDepthCatagory(int type = 0) {
            var tokenMerchant = _iMerchantService.Get(t_RequestMethod.merchant_no);
            var filter = PredicateBuilder.True<Category>();
            filter = filter.And(o => o.MerchantId == tokenMerchant.id && o.ParentId == 0 && o.IsDeleted == false && o.IsDisabled == false && o.Type == type);
            return context.Categories.Where(filter).FromCache<Category, token_category_dto>("Category");
        }

        /// <summary>
        /// 新增或修改拓垦商城分类
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="merchantId"></param>
        /// <returns></returns>
        public bool AddOrUpdateTokenCategory(token_category_dto dto, long merchantId) {
            dto.merchant_id = merchantId;
            if (dto.depth == 2) {
                if (dto.parent_id == 0)
                    throw new ServerErrorException("请选择一级分类");
                dto.path = dto.parent_id.ToString();
            } else {
                dto.path = string.Empty;
                dto.parent_id = 0;
            }
            if (dto.sort == 0)
                dto.sort = (context.Categories.Where(o => o.MerchantId == merchantId && o.ParentId == dto.parent_id && o.IsDeleted == false).Max(o => (int?)o.Sort) ?? 0) + 1;
            if (dto.id == 0) {//新增
                if (context.Categories.Exist(o => o.MerchantId == merchantId && o.ParentId == dto.parent_id && o.Name == dto.name && o.IsDeleted == false && o.Type == dto.type))
                    throw new ServerErrorException("品类名称不能重复");
                var model = dto.ToDtoObject<Category>();
                model.UpdateTime = DateTime.Now;
                context.Categories.Add(model);
            } else {//修改
                var model = context.Categories.FindById(dto.id);
                if (context.Categories.Exist(o => o.MerchantId == merchantId && o.Id != dto.id && o.ParentId == dto.parent_id && o.Name == dto.name && o.IsDeleted == false))
                    throw new ServerErrorException("品类名称不能重复");
                dto.ToDtoObject(model);
                model.UpdateTime = DateTime.Now;

            }
            return _iUnitOfWork.Commit("Category") > 0;
        }
        /// <summary>
        /// 删除拓垦商城分类
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool RemoveTokenCategory(long id) {
            var model = context.Categories.FindById(id);
            model.IsDeleted = true;
            model.UpdateTime = DateTime.Now;
            return _iUnitOfWork.Commit("Category") > 0;
        }
        /// <summary>
        /// 更新拓垦分类状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public bool UpdateTokenCategoryStatus(long id, int status) {
            var model = context.Categories.FindById(id);
            if (status == 0)
                model.IsDisabled = false;
            else if (status == 1)
                model.IsDisabled = true;
            model.UpdateTime = DateTime.Now;
            return _iUnitOfWork.Commit("Category") > 0;
        }
        #endregion

        /// <summary>
        /// 查询子类、将子类放在children中
        /// </summary>
        /// <param name="merchant_id"></param>
        /// <param name="type">0 所有 1 商城 2 集市</param>
        /// <returns></returns>
        public List<category_ex> GetAll(long merchant_id,int type=0) {
            var filter = PredicateBuilder.True<Category>();
            filter = filter.And(c=> c.MerchantId == merchant_id);
            if (type == 1) {
                filter = filter.And(c => c.IsDeleted == false && c.IsDisabled == false && c.Type == 0);
            } else if (type == 2) {
                filter = filter.And(c => c.IsDeleted == false && c.IsDisabled == false && c.Type == 1);
            }
            return context.Categories.Where(filter).OrderBy(c => c.Sort).FromCache((IQueryable<Category> query) => {
                var list = query.ProjectTo<Category, category_ex>();
                var dto = list.Where(c => c.parent_id == 0).ToList();
                getChilds(list, dto);
                return dto;
            });
        }

        private void getChilds(IEnumerable<category_ex> list, IEnumerable<category_ex> child) {
            foreach (var item in child) {
                var c1 = list.Where(c => c.parent_id == item.id).ToList();
                item.children = c1;
                if (c1.Count > 0)
                    getChilds(list, c1);
            }
        }

        public category_dto Get(long id) {
            var query = context.Categories.Where(c => c.Id == id);
            return query.FromCacheFirstOrDefault<Category, category_dto>("Category");
        }
        public category_dto GetCategoryByName(string name) {
            var query = context.Categories.Where(x => x.Name == name);
            return query.FromCacheFirstOrDefault<Category, category_dto>("Category");
        }

        public long Save(category_model dto) {
            long result = 0;
            if (dto.id > 0)
                result = Update(dto);
            else
                result = Add(dto);
            return result;
        }

        public long Add(category_model dto) {
            var merchant = _iMerchantService.Get(dto.bind_no);
            var model = dto.ToDtoObject<Category>();
            model.MerchantId = merchant.id;
            if (model.ParentId == 0) {
                model.Depth = 1;
                model.Path = string.Empty;
            } else {
                var parent = context.Categories.FindById(model.ParentId);
                model.Depth = parent.Depth + 1;
                model.Path = string.IsNullOrEmpty(parent.Path) ? parent.Id.ToString() : string.Format("{0}-{1}", parent.Path, parent.Id);
            }
            if (model.Depth > 3)
                throw new ServerErrorException("层级不得大于三层");
            var prev_max_sort = context.Categories.Where(c => c.ParentId == model.ParentId).Select(c => (int?)c.Sort).Max();
            model.Sort = prev_max_sort ?? dto.sort;
            context.Categories.Add(model);
            int result = _iUnitOfWork.Commit("Category");
            return model.Id;
        }

        public long Update(category_model dto) {
            if (dto.id == dto.parent_id)
                throw new ServerErrorException("上级不能是本身");
            var model = context.Categories.FindById(dto.id);
            var old_depth = model.Depth;
            string old_path = string.IsNullOrEmpty(model.Path) ? string.Empty : string.Format("-{0}-", model.Path);
            bool unchanged_Parent = dto.parent_id == model.ParentId;
            dto.ToDtoObject(model);

            if (!unchanged_Parent) {
                if (model.ParentId == 0) {
                    model.Depth = 1;
                    model.Path = string.Empty;
                } else {
                    var parent = context.Categories.FindById(model.ParentId);
                    if (parent == null)
                        throw new ServerErrorException("找不到上级");
                    if (string.Format("-{0}-", parent.Path).Contains(string.Format("-{0}-", model.Id)))
                        throw new ServerErrorException(string.Format("{0}原来是{1}的下级，不能调整", parent.Name, model.Name));
                    model.Depth = parent.Depth + 1;
                    model.Path = string.IsNullOrEmpty(parent.Path) ? parent.Id.ToString() : string.Format("{0}-{1}", parent.Path, parent.Id);
                }
                if (model.Depth > 3)
                    throw new ServerErrorException("层级不得大于三层");
                //修改下级的Path
                var childs = (from item in context.Categories
                              where ("-" + item.Path + "-").Contains("-" + model.Id + "-")
                              select item).ToList();
                foreach (var child in childs) {
                    if (old_depth > model.Depth) {
                        //升级,更新数据的新path是空时，子集的旧path用-换，否则旧path换更新数据的新path
                        bool is_frist = string.IsNullOrEmpty(model.Path);
                        child.Path = string.Format("-{0}-", child.Path).Replace(old_path, is_frist ? "-" : string.Format("-{0}-", model.Path)).Trim('-');
                    } else if (old_depth == model.Depth) {
                        //平移,用旧path换新path
                        child.Path = string.Format("-{0}-", child.Path).Replace(old_path, string.Format("-{0}-", model.Path)).Trim('-');
                    } else {
                        //降级，更新数据的旧path是空时时，子集的旧path前加更新数据的新path
                        if (string.IsNullOrEmpty(old_path))
                            child.Path = model.Path + "-" + child.Path;
                        else
                            child.Path = string.Format("-{0}-", child.Path).Replace(old_path, string.Format("-{0}-", model.Path)).Trim('-');
                    }
                    child.Depth = child.Path.Split('-').Length + 1;
                }
            }

            int result = _iUnitOfWork.Commit("Category");
            return model.Id;
        }

        public int Update(long id, int sort) {
            var model = context.Categories.FindById(id);
            model.Sort = sort;
            int result = _iUnitOfWork.Commit("Category");
            return result;
        }

        public int Delete(long id) {
            if (context.Categories.Count(c => c.ParentId == id) > 0)
                throw new ServerErrorException("有下级不可以删除");
            context.Categories.Remove(id);
            int result = _iUnitOfWork.Commit("Category");
            return result;
        }
        public ApiResultMessage DeleteCategory(long id) {
            if (context.Categories.Count(c => c.ParentId == id) > 0)
                throw new ServerErrorException("有下级不可以删除");
            var category = context.Categories.FirstOrDefault(c => c.Id == id);
            context.Categories.Remove(category);
            int result = _iUnitOfWork.Commit("Category");
            if (result > 0)
                return ApiResultToJson.Success("删除成功");
            else
                return ApiResultToJson.Fail("删除失败");
        }


    }
}